package SpringDemo.IOC.com.junjie.framework.context.support;

import SpringDemo.IOC.com.junjie.framework.beans.BeanDefinition;
import SpringDemo.IOC.com.junjie.framework.beans.MutablePropertyValues;
import SpringDemo.IOC.com.junjie.framework.beans.PropertyValue;
import SpringDemo.IOC.com.junjie.framework.beans.factory.support.BeanDefinitionRegistry;
import SpringDemo.IOC.com.junjie.framework.beans.factory.xml.XmlBeanDefinitionReader;
import SpringDemo.IOC.com.junjie.framework.util.StringUtil;

import java.lang.reflect.Method;

public class ClassPathXmlApplicationContext extends AbstractApplicationContext{

    public ClassPathXmlApplicationContext(String config){
        this.config = config;
        beanDefinitionReader = new XmlBeanDefinitionReader();

        try {
            refresh();
            System.out.println("已加载的 Bean 定义: " + beanDefinitionReader.getBeanDefinitionRegistry().getBeanDefinitionNames());
        } catch (Exception e) {

        }
    }

    @Override
    public Object getBean(String name) throws Exception {
        //判断Bean是否在单例缓存中存在,如果有直接返回,没有则创建
        Object beanObj = singletonMap.get(name);
        if (beanObj != null) {
            return beanObj;
        }
        //不存在,则创建Bean
        //1,根据Bean名称获取Bean定义对象
        BeanDefinitionRegistry bDR = beanDefinitionReader.getBeanDefinitionRegistry();
        BeanDefinition bD = bDR.getBeanDefinition(name);
        //2,根据Bean定义对象反射创建Bean实例对象
        //2.1,根据Bean定义对象中的类名,获取Class对象
        Class<?> clazz = Class.forName(bD.getClassName());
        //2.2,根据Class对象,反射创建Bean实例对象
        beanObj = clazz.newInstance();

        //4,对Bean实例对象进行依赖注入
        //4.1,获取Bean定义对象中的属性值集合
        MutablePropertyValues propertyValues = bD.getPropertyValues();
        //4.2,遍历属性值集合,对Bean实例对象进行依赖注入
        for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
            //4.2.1,获取属性名
            String id = propertyValue.getName();
            //4.2.2,获取属性值
            String ref = propertyValue.getRef();
            //4.2.3,获取属性值
            String value = propertyValue.getValue();
            //4.2.4,根据属性值类型,进行依赖注入
            if (ref != null && !"".equals(ref)) {
                Object bean = getBean(ref);
                //获取setter方法名
                String methodName = StringUtil.getMethodName(ref);
                //4.2.4.1,根据setter方法名,进行依赖注入
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if (method.getName().equals(methodName)) {
                        method.invoke(beanObj, bean);
                    }
                }
            }

            if (value != null && !"".equals(value)) {
                //获取setter方法名
                String methodName = StringUtil.getMethodName(id);
                //4.2.4.2,根据setter方法名,进行依赖注入
                Method method = clazz.getMethod(methodName, String.class);
                method.invoke(beanObj, value);
            }
        }
        //3,将Bean实例对象添加到单例缓存池中
        singletonMap.put(name, beanObj);
        return beanObj;
    }

    @Override
    public <T> T getBean(String name, Class<? extends T> type) throws Exception {
        Object bean = getBean(name);
        if (bean == null) {
            return null;
        }
        return type.cast(bean);
    }
}
